library Unit initializer Init requires /*
    */ MoveSpeedXGUI /*
    */ LinkedList /*
    */ Item /*
    */ Buff /*
    */


    /*
    --------------------------------------------------------------------------
    # 单位物品
    --------------------------------------------------------------------------
    * param 
    */
    module UnitItemModule
        List m_itemList
        
        method getItemList takes nothing returns List
            if this.m_itemList <= 0 then
                set this.m_itemList = List.create()
            endif
            return this.m_itemList
        endmethod

        method releaseUnitItem takes nothing returns nothing
            call this.m_itemList.destroy()
            set this.m_itemList = 0
        endmethod


        method addItem takes Item itemT returns nothing
            local List list = getItemList()
            call Link.create(list, itemT)
        endmethod

        method removeItem takes Item itemT returns nothing
            local List list = getItemList()
            local Link link = list.first
            local Item itd = 0
            
            loop
                exitwhen link <= 0
                set itd = Item(link.data)
                if itd > 0 and itd == itemT then
                    exitwhen true
                else
                    set itd = 0
                endif
                set link = link.next
            endloop

            if itd > 0 and link > 0 then
                call itd.destroy()
                call link.destroy()
            endif
        endmethod

        method getItemById takes integer itemId returns Item
            local List list = getItemList()
            local Link link = list.first
            local Item itd = 0
            
            loop
                exitwhen link <= 0
                set itd = Item(link.data)
                if itd > 0 and GetItemId(itd.m_item) == itemId then
                    exitwhen true
                else
                    set itd = 0
                endif
                set link = link.next
            endloop

            return itd
        endmethod
        
    endmodule

    /*
    --------------------------------------------------------------------------
    # 单位Buff
    --------------------------------------------------------------------------
    * param 
    */
    module UnitBuffModule
    
        List m_buffList

        method getBuffList takes nothing returns List
            if this.m_buffList <= 0 then
                set this.m_buffList = List.create()
            endif
            return this.m_buffList
        endmethod

        method releaseUnitBuff takes nothing returns nothing
            call this.m_buffList.destroy()
            set this.m_buffList = 0
        endmethod

        method addBuff takes Buff buf returns nothing
            local Link link = getBuffLinkById(buf.m_buffId)

            if link <= 0 then
                call Link.create(getBuffList(), buf)
            endif

            //附加buff到单位
            call buf.applyTo(this.m_unit)
        endmethod

        private method getBuffLinkById takes integer buffId returns Link
            local List list = getBuffList()
            local Link link = list.first
            local Buff buf = 0
            
            loop
                exitwhen link <= 0
                set buf = Buff(link.data)
                if buf > 0 and buf.m_buffId == buffId then
                    return link
                endif
                set link = link.next
            endloop
            
            return 0
        endmethod

        method removeBuff takes Buff bufd returns nothing
            local List list = getBuffList()
            local Link link = list.first
            local Buff buf = 0
            local Buff temp
            
            loop
                exitwhen link <= 0
                set temp = Buff(link.data)
                if temp > 0 and temp == bufd then
                    set buf = temp
                    exitwhen true
                endif
                set link = link.next
            endloop
            
            if buf > 0 then
                call link.destroy()
                call bufd.destroy()
            endif
        endmethod

        method getBuffById takes integer buffId returns Buff
            local List list = getBuffList()
            local Link link = list.first
            local Buff buf = 0
            local Buff temp
            
            loop
                exitwhen link <= 0
                set temp = Buff(link.data)
                if temp > 0 and temp.m_buffId == buffId then
                    set buf = temp
                    exitwhen true
                endif
                set link = link.next
            endloop
            
            if buf == 0 and GetUnitAbilityLevel(this.m_unit, buffId) > 0 then
                set buf = Buff.create(buffId)
                set buf.m_unit = this.m_unit

                call addBuff(buf)
            endif

            return buf
        endmethod

    endmodule
    
    /*
    --------------------------------------------------------------------------
    # 单位对象
    --------------------------------------------------------------------------
    */
    struct Unit extends array
        implement Property

        implement UnitItemModule
        implement UnitBuffModule

        delegate UnitType m_unitType

        unit m_unit

        static method get takes unit u returns Unit
            local Unit this = Unit(GetUnitId(u))
            if this.m_unit != null and this.m_unit == u then
                return this
            endif

            //debug call BJDebugMsg("Unit.get: " + GetUnitName(u) + "|" + I2S(this))

            set this.m_unit = u
            set this.m_unitType = UnitType.create(GetUnitTypeId(u))
            
            return this
        endmethod

        method destroy takes nothing returns nothing
            call this.releaseUnitItem()
            call this.releaseUnitBuff()
            call DestroyMoveSpeedStruct(m_unit)
            call RemoveUnit(m_unit)

            set m_unitType = 0
            set m_unit = null
        endmethod

        method getHeroPrimaryValue takes nothing returns integer
            local string pr = this.m_primary
            if not IsUnitType(this.m_unit, UNIT_TYPE_HERO) then
                return 0
            endif

            if pr == "STR" then
                return GetHeroStr(this.m_unit, true)
            elseif pr == "AGI" then
                return GetHeroAgi(this.m_unit, true)
            elseif pr == "INT" then
                return GetHeroInt(this.m_unit, true)
            endif
            return 0
        endmethod

        method getAttackSpeed takes nothing returns real
            return this.m_attackSpeed
        endmethod

        method setAttackSpeed takes real speed returns nothing
            set this.m_attackSpeed = speed
        endmethod

        method addAttackSpeed takes real speed returns nothing
            call this.setAttackSpeed(getAttackSpeed() + speed)
        endmethod

        method getMoveSpeed takes nothing returns real
            if not (this.m_moveSpeed > 0) then
                set this.m_moveSpeed = GetUnitMoveSpeedX(this.m_unit)
            endif
            return this.m_moveSpeed
        endmethod

        method setMoveSpeed takes real value returns nothing
            if value > 1500 then
                set value = 1500
            elseif value < 0 then
                set value = 0
            endif
            set this.m_moveSpeed = value
            call SetUnitMoveSpeedX(this.m_unit, value)
        endmethod

        method addMoveSpeed takes real value returns nothing
            local real newSpeed = 0
            if value != 0 then
                set newSpeed = getMoveSpeed() + value
                call this.setMoveSpeed(newSpeed)
            endif
        endmethod

        method setPosition takes real x, real y, real z returns nothing
            call SetUnitX(this.m_unit, x)
            call SetUnitY(this.m_unit, y)
            if z > 0 then
                call SetUnitFlyHeight(this.m_unit, z, 0.00)
            endif
        endmethod

        method addAbility takes integer abilityId returns boolean
            if GetUnitAbilityLevel(this.m_unit, abilityId) == 0 then
                call UnitAddAbility(this.m_unit, abilityId)
                call UnitMakeAbilityPermanent(this.m_unit, true, abilityId)
                return true
            endif
            return false
        endmethod

        method getRegenHP takes nothing returns real
            return this.m_regenHP
        endmethod

        method setRegenHP takes real hp returns nothing
            set this.m_regenHP = hp
        endmethod

        method addRegenHP takes real hp returns nothing
            set this.m_regenHP = this.m_regenHP + hp
        endmethod

        method getRegenMP takes nothing returns real
            return this.m_regenMP
        endmethod

        method setRegenMP takes real mp returns nothing
            set this.m_regenMP = mp
        endmethod

        method addRegenMP takes real mp returns nothing
            set this.m_regenMP = this.m_regenMP + mp
        endmethod

    endstruct


    // 初始化单位
    private function InitUnit takes unit u returns nothing
        //debug call BJDebugMsg(GetUnitName(u) + " with ID " + I2S(GetUnitId(u)) + " entered the map.")
    endfunction

    // 释放单位
    private function ReleaseUnit takes unit u returns nothing
        call Unit.get(u).destroy()
    endfunction

    private function Init takes nothing returns nothing
        //单位进入地图
        call OnUnitIndexed(InitUnit)
        //单位离开地图
        call OnUnitDeindexed(ReleaseUnit)
    endfunction

endlibrary